<?php
/**
 * Copyright 2013 Marek Kaszewski
 *
 * This file is part of the JHUB1 Online Community Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace Tools\Controller;

use Application\Model\Endpoint\PrototypeFactory;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Session\Container;
use Zend\Console\Request as ConsoleRequest;
use Application\Entity\BO\UsersBO;
use Application\Entity\BO\AgentsBO;
use Application\Entity\BO\EndpointValuesBO;
use Application\Entity\BO\EndpointTypesBO;
use Doctrine\ORM\Query;

class AgentsController extends AbstractActionController
{
    public function createAction()
    {
        $request = $this->getRequest();
        if (!$request instanceof ConsoleRequest) {
            throw new \RuntimeException('You can only use this action from a console!');
        }
        $isVerbose = $request->getParam('verbose', false) || $request->getParam('v', false);
        $isResult = $request->getParam('result', false) || $request->getParam('r', false);
        $userEmail = $request->getParam('owner');
        $agentName = $request->getParam('name');
        $agentDescr = $request->getParam('descr');
        $agentId = $request->getParam('id');
        $operation = $request->getParam('operation');
        switch ($operation) {
            case 'create':
                $userBO = new UsersBO($this->getServiceLocator());
                $existUserPO = $userBO->getUserByEmail($userEmail);
                if (null == $existUserPO) {
                    echo 'User: ' . $userEmail . ' not found.' . PHP_EOL;
                } else {
                    if ($isVerbose) {
                        echo 'User: ' . $userEmail . ' found. Creating Agent.' . PHP_EOL;
                    }
                    $agentsBO = new AgentsBO($this->getServiceLocator());
                    $agentPO = $agentsBO->addAgent($existUserPO, $agentName, $agentDescr);
                    if ($isVerbose) {
                        echo 'Agent has been created: ' . $agentPO->getUserame() . PHP_EOL;
                    }
                    if ($isResult) {
                        echo $agentPO->getUserame();
                    }
                }
                exit;
            case 'addresses':
                echo 'show addresses';
                exit;
            case 'status':
                $agent = $this->getAgent($agentId);
                echo $agent->toString();
                exit;
        }
    }


    private function findAgent($agentId)
    {
        $em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
        $qb = $em->createQueryBuilder();
        $qb->select('a')
            ->from('\Application\Entity\Agents', 'a')
            ->where('a.username = :username')
            ->setParameters(array('username' => $agentId));
        return $qb->getQuery()->getResult(Query::HYDRATE_OBJECT);
    }

    private function getAgent($agentId)
    {
        $agents = $this->findAgent($agentId);
        if ($agents != null) {
            if (count($agents) > 0) {
                return $agents[0];
            }
        }
        return null;
    }

    public function valuesAction()
    {
        $request = $this->getRequest();
        if (!$request instanceof ConsoleRequest) {
            throw new \RuntimeException('You can only use this action from a console!');
        }
        $isVerbose = $request->getParam('verbose', false) || $request->getParam('v', false);
        $agentId = $request->getParam('agentId');
        $valueName = $request->getParam('name');
        $value = $request->getParam('value');
        $operation = $request->getParam('operation');
        switch ($operation) {
            case 'insert':
                $epvBO = new EndpointValuesBO($this->getServiceLocator());
                $agent = $this->getAgent($agentId);
                if (null == $agent) {
                    echo 'Value ' . $valueName . ' (' . $value . ') has NOT been added. Agent not found.' . PHP_EOL;
                } else {
                    $epvPO = $epvBO->insertValue($agent, $valueName, $value);
                    if ($isVerbose) {
                        echo 'Value ' . $valueName . ' (' . $value . ') has been added.' . PHP_EOL;
                    }
                }
                exit;
            case 'list':
                echo 'list';
                exit;
            case 'status':
                echo 'Stats for agent:                          ' . $agentId . PHP_EOL;
                echo 'Total records for the agent:              ' . $this->countTotalAgentsReadings($agentId) . PHP_EOL;
                echo 'Agents endpoints with records number:     ' . PHP_EOL;
                echo $this->getEndpointsList($agentId) . PHP_EOL;
                exit;
        }
    }

    private function countTotalAgentsReadings($agentId)
    {
        $em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
        $qb = $em->createQueryBuilder();
        $qb->select('count(a.agentUsername)')
            ->from('\Application\Entity\EndpointValues', 'a')
            ->where('a.agentUsername = :username')
            ->setParameters(array('username' => $agentId));
        $result = $qb->getQuery()->getSingleResult();
        if (count($result) > 0) {
            return $result[1];
        }
        return 0;
    }

    private function findEndpointsList($agentId)
    {
        // get endpoinds list
        $em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
        $qb = $em->createQueryBuilder();
        $qb->select('a')
            ->from('\Application\Entity\EndpointValues', 'a')
            ->where('a.agentUsername = :username')
            ->groupBy('a.name')
            ->setParameters(array('username' => $agentId));
        $results = $qb->getQuery()->getArrayResult();
        //count endpoinds occurence
        $endpoints = array();
        if (count($results) > 0) {
            foreach ($results as $result) {
                $qb2 = $em->createQueryBuilder();
                $qb2->select('count(b.name)')
                    ->from('\Application\Entity\EndpointValues', 'b')
                    ->where('b.agentUsername = :username')
                    ->andWhere('b.name = :name')
                    ->setParameters(array('username' => $agentId, 'name' => $result['name']));
                $resultb = $qb2->getQuery()->getSingleResult();
                $endpoints[] = array('name' => $result['name'], 'oc' => $resultb[1]);
            }
        }
        return $endpoints;
    }

    private function getEndpointsList($agentId)
    {
        $endpoints = $this->findEndpointsList($agentId);
        foreach ($endpoints as $endpoint) {
            echo '      ' . $endpoint['name'];
            echo '      ' . $endpoint['oc'] . PHP_EOL;
        }
    }

    public function endpointsAction()
    {
        $request = $this->getRequest();
        if (!$request instanceof ConsoleRequest) {
            throw new \RuntimeException('You can only use this action from a console!');
        }
        $isVerbose = $request->getParam('verbose', false) || $request->getParam('v', false);
        $operation = $request->getParam('operation');
        $userEmail = $request->getParam('owner');
        $name = $request->getParam('name', '');
        $descr = $request->getParam('descr', '');
        $clazz = $request->getParam('class', '');
        switch ($operation) {
            case 'insert':
                if ($clazz == '') {
                    echo 'Class not specified.' . PHP_EOL;
                    exit;
                }
                $classInstance = PrototypeFactory::getInstance($clazz);
                if ($classInstance == null) {
                    echo 'Class is not valid.' . PHP_EOL;
                    echo 'Valid classes: ' . PrototypeFactory::getValidClasses() . '.' . PHP_EOL;
                    exit;
                }
                $userBO = new UsersBO($this->getServiceLocator());
                $existUserPO = $userBO->getUserByEmail($userEmail);
                if (null == $existUserPO) {
                    echo 'User: ' . $userEmail . ' not found.' . PHP_EOL;
                } else {
                    if ($isVerbose) {
                        echo 'User: ' . $userEmail . ' found. Creating endpoint type.' . PHP_EOL;
                    }
                    $types = new EndpointTypesBO($this->getServiceLocator());
                    $avPO = $types->insertValue($existUserPO, $name, $descr, $clazz, $classInstance);
                    if ($isVerbose) {
                        echo 'Endpoint type has been created (ID): ' . $avPO->getId() . PHP_EOL;
                    }
                }
                exit;
            case 'list-types':
                $userBO = new UsersBO($this->getServiceLocator());
                $existUserPO = $userBO->getUserByEmail($userEmail);
                if (null == $existUserPO) {
                    echo 'User: ' . $userEmail . ' not found.' . PHP_EOL;
                } else {
                    echo 'User: ' . $userEmail . ' found. List of the endpoint types:' . PHP_EOL;
                    $endpoints = $existUserPO->getEndpointTypes();
                    foreach($endpoints as $endpoint)
                    {
                        echo $endpoint->toString() . PHP_EOL;
                        echo '|-----------------------------------------------------------------' . PHP_EOL;
                    }
                    echo 'Endpoints in total: ' . count($endpoints) . PHP_EOL;
                }
                exit;
            case 'list-values':
                $userBO = new UsersBO($this->getServiceLocator());
                $existUserPO = $userBO->getUserByEmail($userEmail);
                $ag = new AgentsBO($this->getServiceLocator());
                $agents = $ag->getAgentsList($existUserPO);
                $epv = new EndpointValuesBO($this->getServiceLocator());
                $res = $epv->getAllEndpoints($agents);
                $totalEndpoints = count($res);
                $res2 = $epv->checkForNewEndpoints($agents);
                $undefinedEndpoints = count($res2);
                foreach($res as $re) {
                    if(array_key_exists( $epv->getAddress($re) , $res2 ))
                    {
                        echo '* ';
                    }
                    else
                    {
                        echo '  ';
                    }
                    echo $epv->getAddress($re) . PHP_EOL;
                }
                $def = $totalEndpoints - $undefinedEndpoints;
                echo '#---------------------------------------' . PHP_EOL;
                echo 'Defined endpoints:               ' . $def . PHP_EOL;
                echo 'Undefined endpoints:             ' . $undefinedEndpoints . PHP_EOL;
                echo '                             -----------' . PHP_EOL;
                echo 'Total endpoints registered:      ' . $totalEndpoints . PHP_EOL;
                exit;
        }
    }
}
